from base.exception.IllegalArgumentException import IllegalArgumentException
import ctypes

LongLen = 64

# parameter long int int
# return long
def unpack(bits, start, finish):
    if (isinstance(bits, str)):
        return unpackStr(bits, start, finish)
    checkWithFinish(start, finish)
    if (finish == 0):
        return 0
    # Remove top bits by moving up. Clear bottom bits by them moving down.
    num = (bits << (LongLen - finish))
    digit = ((LongLen - finish) + start)
    return unsigned_right_shitf(num, digit)

# parameter long long int int
# return long
def pack(bits, value, start, finish):
    checkWithFinish(start, finish)
    bits = clear_2(bits, start, finish)
    # long
    mask = mask_2(start, finish)
    bits = bits | ((value << start) & mask)
    return bits

# parameter String int int
# return long
def unpackStr(str, startChar, finishChar):
    s = str[startChar, finishChar]
    return int(s, base=16)

'''
* Set the bits specified.
*
* @param bits     Pattern
* @param bitIndex
* @return Modified pattern
'''
# return long
def set(bits, bitIndex):
    check(bitIndex)
    return set(bits, bitIndex)


'''
* Set the bits from start (inc) to finish (exc) to one
*
* @param bits   Pattern
* @param start  start (inclusive)
* @param finish finish (exclusive)
* @return Modified pattern
'''
# return long
def set2(bits, start, finish):
    checkWithFinish(start, finish)
    return set_2(bits, start, finish)


'''
* Test whether a bit is the same as isSet
*
* @param bits     Pattern
* @param isSet    Test whether is set or not.
* @param bitIndex Bit index
* @return Boolean
'''
# return boolean
def test(bits, isSet, bitIndex):
    check(bitIndex)
    return test_(bits, isSet, bitIndex)


'''
* Test whether a bit is set
*
* @param bits     Pattern
* @param bitIndex Bit index
* @return Boolean
'''
# return boolean
def isSet(bits, bitIndex):
    check(bitIndex)
    return test_(bits, True, bitIndex)


'''
* Test whether a range has a specific value or not
*
* @param bits   Pattern
* @param value  Value to test for
* @param start  start (inclusive)
* @param finish finish (exclusive)
* @return Boolean
'''
# parameter 
# return boolean
def test2(bits, value, start, finish):
    checkWithFinish(start, finish)
    return test_2(bits, value, start, finish)


'''
* Get the bits from start (inclusive) to finish (exclusive), leaving them
* aligned in the long. See also:@link #unpack which returns the value found at
* that place.
*
* @param bits
* @param start
* @param finish
* @return long
* @see #unpack(long, int, int)
'''
# parameter 
# return long
def access(bits, start, finish):
    checkWithFinish(start, finish)
    return access_2(bits, start, finish)


'''
* Clear the bit specified.
*
* @param bits
* @param bitIndex
* @return long
'''
# parameter 
# return long
def clear(bits, bitIndex):
    check(bitIndex)
    return clear_(bits, bitIndex)


'''
* Clear the bits specified.
*
* @param bits
* @param start
* @param finish
* @return long
'''
# parameter 
#return
def clear2(bits, start, finish):
    checkWithFinish(start, finish)
    return clear_2(bits, start, finish)


'''
* Create a mask that has ones between bit positions start (inc) and finish
* (exc), and zeros elsewhere.
*
* @param start
* @param finish
* @return long
'''
# parameter 
# return long
def mask(start, finish):
    checkWithFinish(start, finish)
    return mask_2(start, finish)


'''
* Create a mask that has zeros between bit positions start (inc) and finish
* (exc), and ones elsewhere
*
* @param start
* @param finish
* @return long
'''
# parameter int int 
# return long
def maskZero(start, finish):
    checkWithFinish(start, finish)
    return maskZero_2(start, finish)

# parameter  long int
# return long
def clear_(bits, bitIndex):
    #long
    mask = maskZero_(bitIndex)
    bits = bits & mask
    return bits

# parameter long int int
# return long
def clear_2(bits, start, finish):
    #long
    mask = maskZero_2(start, finish)
    bits = bits & mask
    return bits

# parameter long int
# return long
def set_(bits, bitIndex):
    #long
    mask = mask_(bitIndex)
    return bits | mask

# parameter long int int
# return long
def set_2(bits, start, finish):
    # long
    mask = mask_2(start, finish)
    return bits | mask

# parameter long boolean int
# return boolean
def test_(bits, isSet, bitIndex):
    return isSet == access_(bits, bitIndex)

# parameter long long int int
# return boolean
def test_2(bits, value, start, finish):
    # long
    v = access_2(bits, start, finish)
    return v == value

# parameter long int
# return boolean
def access_(bits, bitIndex):
    # long
    mask = mask_(bitIndex)
    return (bits & mask) != 0

# parameter long int int
# return long
def access_2(bits, start, finish):
    # Alternative
    #     int mask = mask_(start, finish)
    #     return bits & mask
    rightShifted = unsigned_right_shitf((bits << (LongLen - finish)), (LongLen - finish + start))
    return rightShifted << start

# parameter int
# return long
def mask_(bitIndex):
    return 1 << bitIndex

# parameter int int
# return long
def mask_2(start, finish):
    if (finish == 0):
        # Valid args start is zero and so the mask is zero.
        return 0
    mask = -1
    # Order is left to right if the redundant parentheses are removed.
    return (unsigned_right_shitf((mask << (LongLen - finish)), (LongLen - finish + start))) << start

# parameter int
# return long
def maskZero_(bitIndex):
    return ~mask_(bitIndex)

# parameter int int
# return long
def maskZero_2(start, finish):
    return ~mask_2(start, finish)

# parameter long
# return void
def check(bitIndex):
    if (bitIndex < 0 or bitIndex >= LongLen):
        raise IllegalArgumentException("Illegal bit index: " + str(bitIndex))

# parameter 
# return void
def checkWithFinish(start, finish):
    if (start < 0 or start >= LongLen):
        raise IllegalArgumentException("Illegal start: " + str(start))
    if (finish < 0 or finish > LongLen):
        raise IllegalArgumentException("Illegal finish: " + str(finish))
    if (start > finish):
        raise IllegalArgumentException("Illegal range: (" + str(start) + ", " + str(finish) + ")")


def int_overflow(val):
    maxint = 2147483647
    if not -maxint-1 <= val <= maxint:
        val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1
    return val


def unsigned_right_shitf(n,i):
    # 数字小于0，则转为32位无符号uint
    if n<0:
        n = ctypes.c_uint32(n).value
    # 正常位移位数是为正数，但是为了兼容js之类的，负数就右移变成左移好了
    if i<0:
        return -int_overflow(n << abs(i))
    #print(n)
    return int_overflow(n >> i)

if __name__== "__main__" :
    check(-1)